package manager

import (
	"fmt"
	"github.com/google/uuid"
	"gmap-backend/internal/config"
	"gmap-backend/internal/util/commonutil"
	"gmap-backend/internal/util/pathutil"
	"golang.org/x/text/encoding/simplifiedchinese"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

const (
	// 默认执行脚本的代码段为utf-8
	DEFAULT_CODE_PAGE = 65001
)

// SaveCmdFile 保存命令文本到bat文件，内部自动增加chcp 65001头，自动处理换行符等
// useStart false-直接写批处理文件并返回文件地址，true-写完批处理文件后，再写一个用于弹出的批处理文件，并返回后者地址，比如需要看到命令窗口中批处理命令执行过程时使用
func SaveCmdFile(config *config.AppConfig, cmdTxt string, appendCmds string, useStart bool) string {
	return SaveCmdFileWithCodePage(config, cmdTxt, appendCmds, useStart, DEFAULT_CODE_PAGE)
}

// SaveCmdFileWithCodePage 保存命令文本到bat文件，内部自动增加chcp xxx头，自动处理换行符等
// useStart false-直接写批处理文件并返回文件地址，true-写完批处理文件后，再写一个用于弹出的批处理文件，并返回后者地址，比如需要看到命令窗口中批处理命令执行过程时使用
func SaveCmdFileWithCodePage(config *config.AppConfig, cmdTxt string, appendCmds string, useStart bool, codePage int) string {
	defCP := DEFAULT_CODE_PAGE

	// 如果没有命令和后续命令，且是弹出方式执行，则说明只是打开命令提示符操作，使用utf-8编码
	if useStart && "" == cmdTxt && "" == appendCmds {
		cmdTxt = "chcp " + strconv.Itoa(defCP) + "\n" +
			`start` + "\n" +
			"timeout /t 2\n" +
			"exit"
		cmdTxt = commonutil.ReplOsLineSep(cmdTxt)
		batPath := calcNewBatFullPath(config)
		os.WriteFile(batPath, []byte(cmdTxt), 0777)
		return batPath
	}

	// 主体命令：
	// 如果是弹出执行，则说明是脚本，按指定的codepage执行
	// 否则说明是gui程序，固定按utf-8编码执行
	cp := defCP
	if useStart {
		cp = codePage
	}
	cmdTxt = strings.TrimSpace(cmdTxt)
	appendCmds = strings.TrimSpace(appendCmds)
	batPath := calcNewBatFullPath(config)
	if !strings.HasPrefix(cmdTxt, "chcp") {
		cmdTxt = "chcp " + strconv.Itoa(cp) + "\n" + cmdTxt
	}
	if "" != appendCmds {
		cmdTxt += "\n" + appendCmds
	}
	cmdTxt = commonutil.ReplOsLineSep(cmdTxt)
	saveFileByCodePage(batPath, []byte(cmdTxt), cp)
	if !useStart {
		return batPath
	}

	// 需要一个用于弹出的脚本，该脚本始终使用utf-8编码
	cmdTxt = "chcp " + strconv.Itoa(defCP) + "\n" +
		fmt.Sprintf(`start %s`, pathutil.WrapQuotOnPathItems(batPath)) + "\n" +
		"timeout /t 2\n" +
		"exit"
	cmdTxt = commonutil.ReplOsLineSep(cmdTxt)
	batPath = calcNewBatFullPath(config)
	os.WriteFile(batPath, []byte(cmdTxt), 0777)
	return batPath
}

// 按不同codepage保存到文件，目前只支持936与65001，任何其它编码都按65001，等有更多情况出现时再具体实现
func saveFileByCodePage(path string, utf8Cont []byte, codePage int) {
	if 936 == codePage {
		gbkCont, err := simplifiedchinese.GBK.NewEncoder().Bytes(utf8Cont)
		if nil != err {
			panic(err)
		}
		os.WriteFile(path, gbkCont, 0777)
		return
	}
	if 65001 == codePage {
		os.WriteFile(path, utf8Cont, 0777)
		return
	}
	os.WriteFile(path, utf8Cont, 0777)
}

func calcNewBatFullPath(config *config.AppConfig) string {
	uuidStr := strings.ToLower(strings.ReplaceAll(uuid.NewString(), "-", ""))
	return filepath.Join(config.PathConfig.WorkDir, uuidStr+".bat")
}
